/*******************************************************************************
*  file    : mainwindow.cpp
*  created : 20.07.2013
*  author  : Slyshyk Oleksiy (alexSlyshyk@gmail.com)
*******************************************************************************/

#include "smsmainwindow.hpp"
#include "ui_smsmainwindow.h"
#include "versiondialog.h"
#include "smssettingsdialog.hpp"
#include "addmoledialog.hpp"
#include "rpcclient.hpp"
#include "qmaps.h"

#include <QCloseEvent>
#include <QSettings>
#include <QAction>
#include <QTimer>
#include <QDebug>
#include <QIcon>
#include <QSplitter>
#include <QTableView>
#include "devicemodel.hpp"
#include "deviceproxymodel.hpp"
#include "devicestatusboard.hpp"
#include "senddialog.hpp"
#include "QSpreadsheetHeaderView.h"
#include "qbusydialog.hpp"
#include <utils.hpp>

#include <qlogger.hpp>
namespace{
QLogger* l = QLoggerEngine::getLogger("core");
}

smsMainWindow::smsMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::smsMainWindow),
    task_counter_(0)
{
    ui->setupUi(this);

    splitter_ = new QSplitter(this);
    dev_splitter_ = new QSplitter(Qt::Vertical);
    this->setCentralWidget(splitter_);
    dev_table_ = new QTableView;
    header_view_ = new QSpreadsheetHeaderView(Qt::Horizontal, dev_table_);
    dev_table_->setHorizontalHeader(header_view_);
    splitter_->addWidget(dev_table_);
    dev_board_ = new DeviceStatusBoard;
    maps_ = new Maps;
    dev_splitter_->addWidget(dev_board_);
    dev_splitter_->addWidget(maps_);
    splitter_->addWidget(dev_splitter_);

    model_ = new DeviceModel(this);
    proxy_model_ = new DeviceProxyModel(this);
    proxy_model_->setSourceModel(model_);
    dev_table_->setModel(proxy_model_);
    dev_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
    dev_table_->hideColumn(DM_LAST_POS_IDX);
    dev_table_->hideColumn(DM_LAST_POS_DATE_IDX);
    dev_table_->hideColumn(DM_LAST_INFO_IDX);
    dev_table_->hideColumn(DM_TASKS_IDX);
    dev_table_->hideColumn(DM_ID_IDX);
    dev_table_->hideColumn(DM_PASSWD_IDX);
    dev_board_->setModel(proxy_model_);
    connect(dev_table_->selectionModel(),
            SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            dev_board_,
            SLOT(currentChanged(QModelIndex,QModelIndex))  );
    connect(proxy_model_,
            SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
            dev_board_,
            SLOT(dataChanged(QModelIndex,QModelIndex,QVector<int>))  );

    maps_->setModel(proxy_model_);
    connect(dev_table_->selectionModel(),
            SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            maps_,
            SLOT(currentChanged(QModelIndex,QModelIndex))  );
    connect(proxy_model_,
            SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
            maps_,
            SLOT(dataChanged(QModelIndex,QModelIndex,QVector<int>))  );


    restoreSettings();

    QTimer::singleShot(100, this, SLOT(testRpcEcho())  );
    connect(RpcClient::instance(), SIGNAL(serverStateChanged(bool)),
            this,                  SLOT(serverStateChanged(bool)) );
    connect(RpcClient::instance(), SIGNAL(modemStatusChanged(QString)),
            this,                  SLOT(modemStatusChanged(QString)));
    serverStateChanged(false);

    this->createActions();
    this->createToolBar();
    this->createMenu();

    busy_timer_ = new QTimer(this);
    connect(busy_timer_, SIGNAL(timeout()), this, SLOT(timeoutBusyDialog())  );
    connect(RpcClient::instance(), SIGNAL(workingTasksUpdated(int)), this, SLOT(hideBusyDialog()) );

    //QTimer::singleShot(1500,this,SLOT(_testAddMarker()));
}

smsMainWindow::~smsMainWindow()
{
    delete ui;
}

void smsMainWindow::closeEvent(QCloseEvent* e)
{
    saveSettings();
    e->accept();
}

void smsMainWindow::saveSettings()
{
    QSettings s;
    s.beginGroup("main_window");
    s.setValue("geometry",this->saveGeometry());
    s.setValue("state"   ,this->saveState() );
    s.setValue("splitter",splitter_->saveState());
    QStringList col_w;
    for(int i = 0; i < dev_table_->model()->columnCount(); ++i)
        col_w << QString::number(dev_table_->columnWidth(i));
    s.setValue("table_col_width",col_w.join(";"));
    s.endGroup();
}

void smsMainWindow::restoreSettings()
{
    QSettings s;
    s.beginGroup("main_window");
    this->restoreGeometry( s.value("geometry").toByteArray() );
    this->restoreState( s.value("state").toByteArray() );
    splitter_->restoreState(s.value("splitter").toByteArray());
    QStringList col_w;
    col_w = s.value("table_col_width").toString().split(";");
    for(int i = 0; i < std::min(col_w.size(),dev_table_->model()->columnCount()); ++i)
        {
            int w = col_w[i].toInt();
            if(w < 15)
                w = 15;
            dev_table_->setColumnWidth(i,w);
        }

    s.endGroup();
}

void smsMainWindow::createActions()
{
    QIcon icon;

    about_act_ = new QAction(tr("Про программу."),this);
    icon.addPixmap(QPixmap(QStringLiteral(":/images/star.png")), QIcon::Normal, QIcon::Off);
    about_act_->setIcon(icon);
    connect(about_act_, SIGNAL(triggered()), this, SLOT(showAbout()) );

    settings_act_ = new QAction(tr("Настройки"), this);
    icon.addPixmap(QPixmap(QStringLiteral(":/images/setting_tools.png")), QIcon::Normal, QIcon::Off);
    settings_act_->setIcon(icon);
    connect(settings_act_, SIGNAL(triggered()), this, SLOT(showSettings()) );

    add_mole_act_ = new QAction(tr("Добавить устройство"), this);
    icon.addPixmap(QPixmap(QStringLiteral(":/images/add.png")), QIcon::Normal, QIcon::Off);
    add_mole_act_->setIcon(icon);
    connect(add_mole_act_, SIGNAL(triggered()), this, SLOT(showAddDialog())  );

    hide_mole_act_ = new QAction(tr("Спрятать устройства"),this);
    icon.addPixmap(QPixmap(QStringLiteral(":/images/delete.png")), QIcon::Normal, QIcon::Off);
    hide_mole_act_->setIcon(icon);
    connect(hide_mole_act_, SIGNAL(triggered()), this, SLOT(showHideDialog()));

    edit_mole_act_ = new QAction(tr("Редактировать устройство"), this);
    icon.addPixmap(QPixmap(QStringLiteral(":/images/pencil.png")), QIcon::Normal, QIcon::Off);
    edit_mole_act_->setIcon(icon);
    connect(edit_mole_act_, SIGNAL(triggered()), this, SLOT(showEditDialog())  );

    tst_sms_act_ = new QAction(tr("Тестовое сообщение"),this);
    connect(tst_sms_act_, SIGNAL(triggered()), this, SLOT(testSmsOutgoing())  );
    tst_sms_act_->setIcon(QIcon(QStringLiteral(":/images/sms.png")));

    info_sms_act_ = new QAction(tr("Информация"), this);
    connect(info_sms_act_, SIGNAL(triggered()), this, SLOT(sendInfoRequest()) );
    info_sms_act_->setIcon(QIcon(QStringLiteral(":/images/information.png")));

    pos_sms_act_ = new QAction(tr("Позиция"), this);
    connect(pos_sms_act_, SIGNAL(triggered()), this, SLOT(sendPosRequest()) );
    pos_sms_act_->setIcon(QIcon(QStringLiteral(":/images/radiolocator.png")));

    mode0_sms_act_ = new QAction(tr("Усыпить"), this);
    connect(mode0_sms_act_, SIGNAL(triggered()), this, SLOT(sendMode0Request()) );
    mode0_sms_act_->setIcon(QIcon(QStringLiteral(":images/clock_pause.png")));

    mode1_sms_act_ = new QAction(tr("Разбудить"), this);
    connect(mode1_sms_act_, SIGNAL(triggered()), this, SLOT(sendMode1Request()) );
    mode1_sms_act_->setIcon(QIcon(QStringLiteral(":/images/clock_play.png")));


    sort_AZ_act_ = new QAction(tr("Сортировка А-Я"),header_view_);
    connect(sort_AZ_act_, SIGNAL(triggered()), proxy_model_, SLOT(sortAZ()));

    sort_bat_act_ = new QAction(tr("Заряд"),header_view_);
    connect(sort_bat_act_, SIGNAL(triggered()), proxy_model_, SLOT(sortBat()));

    sort_color_act_ = new QAction(tr("Цвет"),header_view_);
    connect(sort_color_act_, SIGNAL(triggered()), proxy_model_, SLOT(sortColor()));

    sort_SMS_date_act_ = new QAction(tr("Посл SMS"),header_view_);
    connect(sort_SMS_date_act_, SIGNAL(triggered()), proxy_model_, SLOT(sortSmsDate()));

    sort_bat_ch_act_ = new QAction(tr("Замена батареи"),header_view_);
    connect(sort_bat_ch_act_, SIGNAL(triggered()), proxy_model_, SLOT(sortBatChange()));

}

void smsMainWindow::createToolBar()
{
    ui->editToolBar->addAction(add_mole_act_);
    ui->editToolBar->addAction(hide_mole_act_);
    ui->editToolBar->addAction(edit_mole_act_);

    ui->mainToolBar->addAction(info_sms_act_);
    ui->mainToolBar->addAction(pos_sms_act_);
    ui->mainToolBar->addAction(mode0_sms_act_);
    ui->mainToolBar->addAction(mode1_sms_act_);
}

void smsMainWindow::createMenu()
{
    ui->about->addAction(about_act_);
    ui->settings->addAction(settings_act_);

    header_view_->addAction(0, sort_AZ_act_);
    header_view_->addAction(0, sort_bat_act_);
    header_view_->addAction(0, sort_color_act_);
    header_view_->addAction(0, sort_SMS_date_act_);
    header_view_->addAction(0, sort_bat_ch_act_);
}

void smsMainWindow::showAbout()
{
    VersionDialog dlg;
    dlg.exec();
}

void smsMainWindow::showSettings()
{
    SmsSettingsDialog dlg;
    dlg.exec();
}

void smsMainWindow::showAddDialog()
{
    AddMoleDialog dlg;
    if(dlg.exec())
        {
            logDebug(l)<<"try add mole";
            RpcClient::instance()->addMole(dlg.phone(),dlg.name(),dlg.passwd(),
                                           dlg.memo(),dlg.bat_change().toString(Utils::datetime_format()));
        }
}

void smsMainWindow::showEditDialog()
{
    AddMoleDialog dlg;
    dlg.setWindowTitle(tr("Править устройство"));
    QModelIndex index = dev_table_->selectionModel()->currentIndex();
    int row = -1;
    if(!index.isValid())
        {
            return;
        }
    row = index.row();
    dlg. setPhone     (proxy_model_->data(proxy_model_->index(row,DM_PHONE_NUMBER_IDX),Qt::DisplayRole).toString() ) ;
    dlg. setName      (proxy_model_->data(proxy_model_->index(row,DM_NAME_IDX),Qt::DisplayRole).toString() ) ;
    dlg. setPasswd    (proxy_model_->data(proxy_model_->index(row,DM_PASSWD_IDX),Qt::DisplayRole).toString() ) ;
    dlg. setMemo      (proxy_model_->data(proxy_model_->index(row,DM_MEMO_IDX),Qt::DisplayRole).toString() ) ;
    dlg. setBatChange (QDateTime::fromString(proxy_model_->data(proxy_model_->index(row,DM_BAT_CHANGE_IDX),
                                                                Qt::DisplayRole).toString(),
                                             Utils::datetime_format()) ) ;
    int id = proxy_model_->data(proxy_model_->index(row,DM_ID_IDX),Qt::DisplayRole).toInt();
    if(dlg.exec())
        {
            RpcClient::instance()->updateMole(dlg.phone(),dlg.name(),dlg.passwd(),
                                              dlg.memo(),dlg.bat_change().toString(Utils::datetime_format()),id);
            logDebug(l)<<"try edit mole";
        }
}

void smsMainWindow::showHideDialog()
{
    QStringList mole_id = chooseIndexes();
    if(mole_id.size())
        RpcClient::instance()->hideMoles(mole_id);
    else
        logError(l)<<QString(tr("Запрос на удаление не отправлен. Список пуст."));
}

void smsMainWindow::testRpcEcho()
{
    RpcClient::instance()->echo("Hello world !");
}

void smsMainWindow::testSmsOutgoing()
{
    int recipient_id = -1;
    recipient_id = proxy_model_->data(dev_table_->currentIndex() ,DM_IDEX_DATA_ROLE).toInt();
    logDebug(l)<<"Send SMS to IDX:"<<recipient_id;
    RpcClient::instance()->addSmsToOutgoing(recipient_id,"adgjmptw;info?");
}

QStringList smsMainWindow::chooseIndexes()
{
    QModelIndexList indexList = dev_table_->selectionModel()->selectedIndexes();
    QVector<int> rows(indexList.size());
    for(int i = 0; i < indexList.size(); ++i)
        rows[i] = indexList[i].row();
    std::sort(rows.begin(),rows.end());
    rows.erase( std::unique(rows.begin(),rows.end()), rows.end() );

    QVector<QStringList> data;
    data.reserve(rows.size());
    for(int row : rows)
        {
            auto index = [this, row](int column)->QVariant
                         { return proxy_model_->data( proxy_model_->index(row,column)); };
            QStringList l;
            l  <<index(DM_NAME_IDX)        .toString()
               <<index(DM_PHONE_NUMBER_IDX).toString()
               <<index(DM_MEMO_IDX)        .toString();
            data.push_back(l);
        }

    SendDialog sd;
    sd.setData(data);
    QStringList mole_id;
    if(sd.exec() == QDialog::Accepted)
        {
            QStringList items = sd.items();
            std::sort(items.begin(), items.end());
            for(int row : rows)
                {
                    auto field = [this, row](int column)->QVariant
                                 { return proxy_model_->data( proxy_model_->index(row,column)); };
                    if(items.contains(field(DM_PHONE_NUMBER_IDX).toString()))
                        mole_id<<field(DM_ID_IDX).toString();
                }
        }
    return mole_id;
}

void smsMainWindow::sendInfoRequest()
{
    QStringList mole_id = chooseIndexes();
    if(mole_id.size())
        {
            RpcClient::instance()->sendInfoRequest(mole_id);
            task_counter_ += mole_id.size();
            showBusyDialog(tr("Запрос информации добавляется в очередь."));
        }
    else
        logError(l)<<QString(tr("Запрос информации не отправлен. Список пуст."));
}

void smsMainWindow::sendPosRequest()
{
    QStringList mole_id = chooseIndexes();
    if(mole_id.size())
        {
            RpcClient::instance()->sendPosRequest(mole_id);
            showBusyDialog(tr("Запрос местоположения добавляется в очередь."));
        }

    else
        logError(l)<<QString(tr("Запрос местоположения не отправлен. Список пуст."));
}

void smsMainWindow::sendMode0Request()
{
    QStringList mole_id = chooseIndexes();
    if(mole_id.size())
        {
            RpcClient::instance()->sendModeRequest(mole_id,0);
            showBusyDialog(tr("Запрос перевода в режим сна добавляется в очередь."));
        }

    else
        logError(l)<<QString(tr("Запрос изменения режима не отправлен. Список пуст."));
}

void smsMainWindow::sendMode1Request()
{
    QStringList mole_id = chooseIndexes();
    if(mole_id.size())
        {
            RpcClient::instance()->sendModeRequest(mole_id,1);
            showBusyDialog(tr("Запрос перевода в режим бодрствования добавляется в очередь."));
        }

    else
        logError(l)<<QString(tr("Запрос изменения режима не отправлен. Список пуст."));
}

void smsMainWindow::serverStateChanged(bool st)
{
    if(st)
        {
            server_status_ = QString(tr("Сервер на связи."));
            RpcClient::instance()->getMoleList();
        }
    else
        {
            server_status_ = QString(tr("Сервер недоступен."));
        }

        ui->statusBar->showMessage(QString("%1 %2").arg(server_status_).arg(modem_status_));
}

void smsMainWindow::modemStatusChanged(const QString& ms)
{
    modem_status_ = ms;
    ui->statusBar->showMessage(QString(tr("%1 %2")).arg(server_status_).arg(modem_status_));
}

void smsMainWindow::testMenuAction()
{
    qDebug()<<Q_FUNC_INFO;
}

void smsMainWindow::_testAddMarker()
{
    logDebug(l)<<Q_FUNC_INFO;
    maps_->addMarker(50.4586831,30.4363376,"Test");
}

void smsMainWindow::showBusyDialog(const QString& txt)
{
    if(busy_dialog_.isNull())
        {
            busy_dialog_ = new QBusyDialog;
        }
    busy_dialog_->setLabelText(txt);
    busy_timer_->start(10000);
    busy_dialog_->show();
}

void smsMainWindow::hideBusyDialog()
{
    if(!busy_dialog_.isNull())
        delete busy_dialog_.data();

    if(busy_timer_->isActive())
        busy_timer_->stop();
}

void smsMainWindow::timeoutBusyDialog()
{
    logError(l)<<QString(tr("Вышел таймаут диалога занятости."));
    task_counter_ = 0;
    hideBusyDialog();
}

